03. MiniFlow 架构

MiniFlow 架构

我们看看如何用 MiniFlow 实现这一图表结构。我们将使用一个 Python 类来表示普通节点。

class Node(object):
    def __init__(self):
        # Properties will go here!

我们知道,每个节点可能会从其他多个节点那接收输入。我们还知道,每个节点都会创建一个输出,这些输出有可能会传递给其他节点。我们添加以下两个列表:一个用于存储对传入节点的引用,另一个用于存储对传出节点的引用。

class Node(object):
    def __init__(self, inbound_nodes=[]):
        # Node(s) from which this Node receives values
        self.inbound_nodes = inbound_nodes
        # Node(s) to which this Node passes values
        self.outbound_nodes = []
        # For each inbound Node here, add this Node as an outbound Node to _that_ Node.
        for n in self.inbound_nodes:
            n.outbound_nodes.append(self)

每个节点将最终计算出一个表示输出的值。我们将 value 初始化为 None,表示该值存在,但是尚未设定。

class Node(object):
    def __init__(self, inbound_nodes=[]):
        # Node(s) from which this Node receives values
        self.inbound_nodes = inbound_nodes
        # Node(s) to which this Node passes values
        self.outbound_nodes = []
        # For each inbound Node here, add this Node as an outbound Node to _that_ Node.
        for n in self.inbound_nodes:
            n.outbound_nodes.append(self)
        # A calculated value
        self.value = None

每个节点都必须能够将值向前传递,并进行反向传播(稍后会详细介绍)。暂时,我们为前向传播添加一个占位符方法。我们将稍后处理反向传播。

class Node(object):
    def __init__(self, inbound_nodes=[]):
        # Node(s) from which this Node receives values
        self.inbound_nodes = inbound_nodes
        # Node(s) to which this Node passes values
        self.outbound_nodes = []
        # For each inbound Node here, add this Node as an outbound Node to _that_ Node.
        for n in self.inbound_nodes:
            n.outbound_nodes.append(self)
        # A calculated value
        self.value = None

    def forward(self):
        """
        Forward propagation.

        Compute the output value based on `inbound_nodes` and
        store the result in self.value.
        """
        raise NotImplemented

可以进行计算的节点

虽然 Node 定义了每个节点都具有的基本属性,但是只有 Node 的特殊子类会出现在图表中。在本次实验练习中,你将构建可以进行计算和存储值的 Node 子类。例如,考虑 NodeInput 子类。

class Input(Node):
    def __init__(self):
        # An Input node has no inbound nodes,
        # so no need to pass anything to the Node instantiator.
        Node.__init__(self)

    # NOTE: Input node is the only node where the value
    # may be passed as an argument to forward().
    #
    # All other node implementations should get the value
    # of the previous node from self.inbound_nodes
    #
    # Example:
    # val0 = self.inbound_nodes[0].value
    def forward(self, value=None):
        # Overwrite the value if one is passed in.
        if value is not None:
            self.value = value

Node 的其他子类不同,Input 子类实际上并不计算任何内容。Input 子类仅仅存储了一个 value,例如数据特征或模型参数(权重/偏置)。

你可以明确地设置 value,或者用 forward() 方法进行设置。该值然后会传递给神经网络的其他节点。

Add 子类

AddNode 的另一个子类,实际上可以进行计算(加法)。

class Add(Node):
    def __init__(self, x, y):
        Node.__init__(self, [x, y])

    def forward(self):
        """
        You'll be writing code here in the next quiz!
        """

注意 __init__ 方法 Add.__init__(self, [x, y]) 的不同之处。Input 类没有传入节点,而 Add 类具有 2 个传入节点 xy,并将这两个节点的值相加。